﻿using Caffeine.Core.Test.TestModel.ModelExtensionTesterModels;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;

namespace Caffeine.Core.Test
{
    [TestClass]
    public class ModelExtensionTester
    {
        [TestMethod]
        public void ClearExtensionTest()
        {
            ModelFactory factory = new ModelFactory();
            TestModelA modelA = factory.CreateModel<TestModelA>();
            Assert.IsNull(modelA.ModelExtension);

            ModelExtension modelExtension = new ModelExtension();
            Boolean extensionMethodCalled = false; 

            factory.ModelExtensions[typeof(TestModelA)] = (model) => 
            {
                extensionMethodCalled = true;
                return modelExtension;
            };

            Assert.AreEqual(modelA.ModelExtension, modelExtension);
            Assert.IsTrue(extensionMethodCalled);
            extensionMethodCalled = false;

            Assert.AreEqual(modelA.ModelExtension, modelExtension);
            Assert.IsFalse(extensionMethodCalled);

            factory.ModelExtensions[typeof(TestModelA)] = null;
            Assert.AreEqual(modelA.ModelExtension, modelExtension);
            Assert.IsFalse(extensionMethodCalled);

            modelA.ClearModelExtension();

            Assert.IsNull(modelA.ModelExtension);
            Assert.IsFalse(extensionMethodCalled);

            factory.ModelExtensions.Remove(typeof(TestModelA));
            Assert.IsNull(modelA.ModelExtension);
            Assert.IsFalse(extensionMethodCalled);

            factory.ModelExtensions[typeof(TestModelB)] = (model) =>
            {
                extensionMethodCalled = true;
                return null;
            };

            Assert.IsNull(modelA.ModelExtension);
            Assert.IsFalse(extensionMethodCalled);

            factory.ModelExtensions[typeof(TestModelA)] = (model) =>
            {
                extensionMethodCalled = true;
                return null;
            };

            Assert.IsNull(modelA.ModelExtension);
            Assert.IsTrue(extensionMethodCalled);
            extensionMethodCalled = false;

            Assert.IsNull(modelA.ModelExtension);
            Assert.IsTrue(extensionMethodCalled);
            extensionMethodCalled = false;
            Boolean modelExtensionPropertyChanged = false;

            modelA.PropertyChanged += (sender, e) =>
            {
                modelExtensionPropertyChanged = modelExtensionPropertyChanged || e.PropertyName == "ModelExtension";
            };

            modelA.ClearModelExtension();
            Assert.IsFalse(modelExtensionPropertyChanged);

            factory.ModelExtensions[typeof(TestModelA)] = (model) =>
            {
                extensionMethodCalled = true;
                return modelExtension;
            };

            Assert.AreEqual(modelA.ModelExtension, modelExtension);
            Assert.IsFalse(modelExtensionPropertyChanged);

            modelA.ClearModelExtension();
            Assert.IsTrue(modelExtensionPropertyChanged);
            modelExtensionPropertyChanged = false;

            modelA.ClearModelExtension();
            Assert.IsFalse(modelExtensionPropertyChanged);

            ModelExtension2 modelExtension2 = new ModelExtension2();

            factory.ModelExtensions[typeof(TestModelB)] = (model) =>
            {
                extensionMethodCalled = true;
                return modelExtension2;
            };

            TestModelB modelB = factory.CreateModel<TestModelB>();
            Assert.AreEqual(modelB.ModelExtension, modelExtension2);
            Assert.IsFalse(modelExtension2.ReleaseCalled);

            modelB.PropertyChanged += (sender, e) =>
            {
                modelExtensionPropertyChanged = modelExtensionPropertyChanged || e.PropertyName == "ModelExtension";
            };

            modelB.ClearModelExtension();
            Assert.IsTrue(modelExtension2.ReleaseCalled);
            Assert.IsTrue(modelExtensionPropertyChanged);
        }

        [TestMethod]
        public void ClearExtensionsForGraphTest()
        {
            ModelFactory factory = new ModelFactory();
            TestModelA modelA = factory.CreateModel<TestModelA>();

            modelA.ChildModel = factory.CreateModel<TestModelA>();
            modelA.ChildModel.ChildModel = factory.CreateModel<TestModelA>();

            factory.ModelExtensions[typeof(TestModelA)] = (model) => 
            {
                return new ModelExtension2();
            };

            Assert.IsNotNull(modelA.ModelExtension);
            Assert.IsNotNull(modelA.ChildModel.ModelExtension);
            Assert.AreNotEqual(modelA.ModelExtension, modelA.ChildModel.ModelExtension);
            Assert.IsNotNull(modelA.ChildModel.ChildModel.ModelExtension);
            Assert.AreNotEqual(modelA.ChildModel.ModelExtension, modelA.ChildModel.ChildModel.ModelExtension);

            factory.ModelExtensions.Remove(typeof(TestModelA));

            modelA.ClearExtensionsForGraph();
            Assert.IsNull(modelA.ModelExtension);
            Assert.IsNull(modelA.ChildModel.ModelExtension);
            Assert.IsNull(modelA.ChildModel.ChildModel.ModelExtension);
        }
    }
}
